/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "GameBuilder.h"

namespace PQBuilder
{
	GameBuilder::GameBuilder()
		: _playing(false),_root(0),_renderWindow(0),_sceneObject(0),_operation(SCENE_OPERATION_CLOSED),
		_mode(GEDIT_MODE_SELECT),_dragObject(0),_axisGizmo(0),_translator(0),
		_mouseX(0),_mouseY(0),_lastMouseX(0),_lastMouseY(0)
	{
		
	}

	void GameBuilder::createFlatTerrain(int slotX,int slotY,int diffuseTexIndex)
	{
		//_sceneObject->createFlatTerrain(slotX,slotY,diffuseTexIndex);

	}


	void GameBuilder::enableSkyDome(bool enabled)
	{
		if(_sceneObject){
			_sceneObject->enableSkyDome(enabled);
		}
	}

	GameBuilder::~GameBuilder()
	{
		if(_sceneObject){
			//SEngine.removeSceneObject(_sceneObject);
		}
		delete _sceneCamera;
		delete _translator;

	}

	void GameBuilder::init(Ogre::String wnd,int width,int height)
	{

		//actual create our graphics engine
		if(_root){
			return;
		}

		//init ogre
		_root=new Ogre::Root();
		if(!_root->restoreConfig()){
			_root->showConfigDialog();
			_root->saveConfig();
		}

		_root->initialise(false);


		Ogre::NameValuePairList params;
		params["externalWindowHandle"] = wnd;
		params["vsync"] = "Yes"; 
		params["gamma"] ="Yes"; 
		params["FSAA"] = "2"; 

		_renderWindow = _root->createRenderWindow(BUILDER_RENDER_WINDOW_NAME, width,height,false,&params);


		defineResource();

		createDefaultScene();
		/*
		_sceneObject=0;
		_sceneObject->getRenderProperty().setBackground(Ogre::ColourValue(0.3,0.3,0.3));
		_sceneObject->getRenderProperty().setAmbient(Ogre::ColourValue(1,1,1));

		//Becareful the input process sequence
		_sceneCamera=new SceneCamera(_sceneObject);
		_axisGizmo=new TransformGizmo(_sceneObject);
		_translator=new InputOpTranslator();
		
		_inited=true;
		*/
		
	}

	void GameBuilder::createDefaultScene()
	{
		if(_sceneObject){
			return;
		}

		_sceneObject=new PQEngine::SceneObject(_renderWindow);
		_sceneObject->getRenderProperty().setBackground(Ogre::ColourValue(0.3,0.3,0.3));
		_sceneObject->getRenderProperty().setAmbient(Ogre::ColourValue(1,1,1));

		//Becareful the input process sequence
		//_sceneCamera=new SceneCamera(_sceneObject);
		//_axisGizmo=new TransformGizmo(_sceneObject);
		//_translator=new InputOpTranslator();

		
	}

	void GameBuilder::loadScene()
	{
		
	}

	void GameBuilder::update(float deltaT)
	{
		if(!_root){
			return;
		}

		//_sceneCamera->update(deltaT);
		//_axisGizmo->update(_mouseX,_mouseY);
		_sceneObject->update(deltaT);
		

		_lastMouseX=_mouseX;
		_lastMouseY=_mouseY;
	}

	void GameBuilder::startGameEngine()
	{
		
	}

	void GameBuilder::ResetScreenResolution(int width,int height)
	{
		if(_sceneObject){
			_sceneObject->resetScreenResolution(width,height);
			
			this->ResetInput();
		}
	}

	void GameBuilder::ResetInput()
	{
		if(!_translator){
			return;
		}

		_translator->ResetInput();
	}

	void GameBuilder::processOps(int x,int y)
	{
		//if this operation is time duration try to close it
		if(closeOperation()){
			//eg. select is mouse left down,now coding let while press we continue select.
			//reset input to force stop it.
			
			return;
		}

		if(processGeneralOps(x,y)){
			
			return;
		}

		if(processObjectOps(x,y)){
			
			return;
		}

		if(processTerrainOps(x,y)){
			
			return;
		}
	}

	bool GameBuilder::closeOperation()
	{
		switch(_operation){
			case SCENE_OPERATION_START_TRANSFORM:
				if(!_translator->isPressed(MOUSE_BUTTON_LEFT)){
					_axisGizmo->stopTransform();
					_operation=SCENE_OPERATION_CLOSED;
					return true;
				}
				break;
			default:
				break;
		}

		return false;
	}


	bool GameBuilder::processGeneralOps(int x,int y)
	{
		if(!_translator){
			return false;
		}
		OpType op=_translator->getOp(SHORTCUT_TYPE_GENERAL);
		switch(op){
			case OP_CAMERA_ROTATE:
				_sceneCamera->rotate(_mouseX,_mouseY,x,y);
				return true;
			case OP_CAMERA_ROTATE_OBJECT:
				_sceneCamera->rotateObject(_mouseX,_mouseY,x,y);
				return true;
			case OP_CAMERA_PAN:
				_sceneCamera->pan(_mouseX,_mouseY,x,y);
				return true;
			case OP_CAMERA_FORWARD:
				_sceneCamera->forward();
				return true;
			case OP_CAMERA_BACKWARD:
				_sceneCamera->backward();
				return true;
			case OP_CAMERA_LEFTWARD:
				_sceneCamera->leftward();
				return true;
			case OP_CAMERA_RIGHTWARD:
				_sceneCamera->rightward();
				return true;
			case OP_CAMERA_UPWARD:
				_sceneCamera->upward();
				return true;
			case OP_CAMERA_DOWNWARD:
				_sceneCamera->downward();
				return true;
			case OP_SELECT:
				processSelectOp();
				
				return true;
			case OP_MODE_TRANSLATE:
				changeEditMode(GEDIT_MODE_TRANSLATE_OBJECT);
				return true;
			case OP_MODE_ROTATE:
				changeEditMode(GEDIT_MODE_ROTATE_OBJECT);
				return true;
			case OP_MODE_SCALE:
				changeEditMode(GEDIT_MODE_SCALE_OBJECT);
				return true;
			case OP_MODE_SELECT:
				changeEditMode(GEDIT_MODE_SELECT);
				return true;
			case OP_NONE:
			default:
				return false;//no operation performed
		}
	}

	void GameBuilder::processSelectOp()
	{
		if(_mode==GEDIT_MODE_TRANSLATE_OBJECT||
			_mode==GEDIT_MODE_ROTATE_OBJECT||
			_mode==GEDIT_MODE_SCALE_OBJECT){//In transfrom mode
			PQEngine::GameObject* obj=_sceneObject->getGameObject();
			if(obj&&obj->isMesh()){//Has object selected and is a movable object(all mesh now movable)
				if(_axisGizmo->isTransforming()){
					return;
				}

				if(_axisGizmo->isGizmoSelected()){
					_axisGizmo->startTransform(_mouseX,_mouseY);
					_operation=SCENE_OPERATION_START_TRANSFORM;
					return;
				}else{
					//if the mouse ray is on current select object,when free transform it on plane
					if(_sceneObject->getObject(_mouseX,_mouseY)==_sceneObject->getGameObject()){
						_axisGizmo->startTransform(_mouseX,_mouseY);
						_operation=SCENE_OPERATION_START_TRANSFORM;
					}else{
						_sceneObject->selectObject(_mouseX,_mouseY);
					}
					
					
					return;
				}
			}
		}
		
		PQEngine::GameObject* obj=_sceneObject->selectObject(_mouseX,_mouseY);
		if(PQEngine::Object::isGameObject(obj)){
			if(obj->isTerrain()){
				//PQEngine::TerrainEditMode mode= _sceneObject->getTerrainEditMode();
				
			}
			
		}

	}

	void GameBuilder::changeEditMode(EditMode mode)
	{
		_mode=mode;
		switch(mode){
			case GEDIT_MODE_SELECT:
				_axisGizmo->setGizmoMode(GIZMO_MODE_SELECT);
				break;
			case GEDIT_MODE_TRANSLATE_OBJECT:
				_axisGizmo->setGizmoMode(GIZMO_MODE_TRANSLATE);
				break;
			case GEDIT_MODE_ROTATE_OBJECT:
				_axisGizmo->setGizmoMode(GIZMO_MODE_ROTATE);
				break;
			case GEDIT_MODE_SCALE_OBJECT:
				_axisGizmo->setGizmoMode(GIZMO_MODE_SCALE);
				break;
			default:
				break;
		}
	}

	bool GameBuilder::processObjectOps(int x,int y)
	{
		if(!_translator){
			return false;
		}
		OpType op=_translator->getOp(SHORTCUT_TYPE_OBJECT);
		switch(op){
			case OP_FRAME_OBJECT:
				_sceneCamera->frameObject();
				return true;
			default:
				return false;//no operation performed
		}

	}

	bool GameBuilder::processTerrainOps(int x,int y)
	{
		return false;
	}

	void GameBuilder::OnKeyDown(int key)
	{
		if(!_translator){
			return;
		}
		_translator->OnKeyDown(key);
		processOps(_mouseX,_mouseY);
	}

	void GameBuilder::OnKeyUp(int key)
	{
		if(!_translator){
			return;
		}
		_translator->OnKeyUp(key);
		processOps(_mouseX,_mouseY);
	}

	void GameBuilder::OnMouseLeftDown(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseLeftDown(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseLeftUp(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseLeftUp(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseRightDown(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseRightDown(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseRightUp(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseRightUp(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseMidDown(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseMidDown(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseMidUp(int x,int y)
	{
		if(!_translator){
			return;
		}
		_translator->OnMouseMidUp(x,y);

		processOps(x,y);

		_mouseX=x;
		_mouseY=y;
	}

	void GameBuilder::OnMouseMove(int x,int y)
	{
		if(!_sceneObject){
			return;
		}

		_sceneObject->OnMouseMove(x,y);
		_translator->OnMouseMove(x,y);


		processOps(x,y);

		_mouseX=x;
		_mouseY=y;

	}

	
	PQEngine::Object* GameBuilder::addGPKResource(std::string path)
	{
		assert(false);
		return 0;
		/*
		PQEngine::Object* object=SEngine.addGPKResource(path);
		
		if(PQEngine::Object::isGameObject(object)){
			PQEngine::GameObject* obj=(PQEngine::GameObject*)object;
			Ogre::Vector3 pos=_sceneObject->getRay(_mouseX,_mouseY).getPoint(PQEngine::GameEngine::OBJECT_FRAME_DISTANCE);
			obj->setPosition(pos);
		}
		
		return object;
		*/

	}

	PQEngine::Object* GameBuilder::createObject(PQEngine::ObjectType type)
	{
		//switch(
		assert(!"Not Implemented!");
		/*
		PQEngine::Object* object= SEngine.createObject(type);

		if(PQEngine::Object::isGameObject(object)){
			PQEngine::GameObject* obj=(PQEngine::GameObject*)object;
			Ogre::Vector3 pos=_sceneObject->getRay(_mouseX,_mouseY).getPoint(PQEngine::GameEngine::OBJECT_FRAME_DISTANCE);
			obj->setPosition(pos);
		}
		
		return object;
		*/
		return 0;
	}

	void GameBuilder::OnDragEnter(SceneDragEvent evt)
	{
		_mouseX=evt.x;
		_mouseY=evt.y;

		this->exec(evt.data,evt.len);
		
		_dragObject=_sceneObject->getGameObject();
		if(!_dragObject){
			return;
		}

		if(PQEngine::Object::isGameObject(_dragObject)){
			PQEngine::GameObject* obj=(PQEngine::GameObject*)_dragObject;
			Ogre::Vector3 pos=_sceneObject->getRay(evt.x,evt.y).getPoint(OBJECT_FRAME_DISTANCE);
			obj->setPosition(pos);
			//obj->setMaterialName(GNgMaterialManager.getWireFrameMaterialName());
		}

	}

	void GameBuilder::OnDragMove(SceneDragEvent evt)
	{
		_mouseX=evt.x;
		_mouseY=evt.y;

		if(PQEngine::Object::isGameObject(_dragObject)){
			PQEngine::GameObject* obj=(PQEngine::GameObject*)_dragObject;
			Ogre::Vector3 pos=_sceneObject->getRay(evt.x,evt.y).getPoint(OBJECT_FRAME_DISTANCE);
			obj->setPosition(pos);
			
		}
	}

	void GameBuilder::OnDrop(SceneDragEvent evt)
	{
		if(PQEngine::Object::isGameObject(_dragObject)){
			PQEngine::GameObject* obj=(PQEngine::GameObject*)_dragObject;
			Ogre::Vector3 pos=_sceneObject->getRay(evt.x,evt.y).getPoint(OBJECT_FRAME_DISTANCE);
			obj->setPosition(pos);
			//obj->setNormalMaterial();
			
			_sceneObject->selectObject(obj->getId());
			_dragObject=0;
		}
	}

	void GameBuilder::exec(char* data,int len)
	{
		assert(false);
		return;

		/*
		PQCore::SerializeDatagram* datagram=new PQCore::SerializeDatagram(data,len);
		PQCore::SerializeParser parser(datagram);
		PQCore::SerializeDataId command=parser.getName();

		switch(command){
			case PQEngine::GDATA_COMMAND_ADD_GPACK_RESOURCE:
			{
				std::string path=parser.getParam()->getString();
				addGPKResource(path);
				break;
			}
			case PQEngine::GDATA_COMMAND_CREATE_OBJECT:
			{
				PQEngine::ObjectType type=parser.getParam()->getObjectType();
				switch(type){
				case PQEngine::OBJECT_TYPE_LIGHT:

					//_sceneObject->createL
					break;
				}

				createObject(parser.getParam()->getObjectType());
				break;
			}
			
			default:
				break;
		}
		delete datagram;
		*/
	}

	void GameBuilder::selectAndFrameObject(int id)
	{
		_sceneCamera->frameObject(id);//there is wired bug here.BUG
		_sceneObject->selectObject(id);//Should be select bug.SELECT BUG.
	}

	PQEngine::SceneRenderProperty& GameBuilder::getRenderProperty()
	{
		return _sceneObject->getRenderProperty();
	}

	void GameBuilder::renderOneFrame()
	{
		if(PQEngine::SceneObject::isActivate(_sceneObject)){
			Ogre::Root::getSingleton().renderOneFrame();
		}
	}

	void GameBuilder::activate()
	{
		assert(false);
		//SEngine.setActiveScene(_sceneObject);
	}

	void GameBuilder::defineResource()
	{
		
	}


}
